# !/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2023/9/8 15:29
# @Author  : xinyingjie
# @File    : main-dev.py
# @Description :  速通高速ETC断面高速仿真发车


from __future__ import absolute_import
from __future__ import print_function

import json
import os
import threading
import uuid
import random
import time
import asyncio
import traci.constants as tc
import sumolib
import traci
from util import sumo_utils, kafka_util
from util.kafka_util import real_vehicle_queue
from util.websocketserver1 import WebSocketServer
import logging

# 全局中心点6323.78,31009.31  12320.04,30723.05  5362.89,27538.55  13320.35,27643.33
GLOBAL_POLYGON_CENTER = [(2156.62, 2207.91), (2237.31, 2204.92),
                         (2248.41, 2087.94), (2119.47, 2089.22)]
# 异常标签
# unlawfulMap = {"多卡多签": "0101", "车型异常": "0102", "ETC无入口信息": "0103", "疑似屏蔽": "0104", "其他异常": "0104", "无号牌": "0105"}
unlawfulMap = {"0101": "0101", "0102": "0102", "0103": "0103"}

def get_logger(log_type):
    # 第一步，创建一个logger
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)  # Log等级总开关
    # 第二步，创建一个handler，用于写入日志文件
    rq = str(time.strftime('%Y%m%d', time.localtime(time.time()))) + '_' + str(log_type)
    log_path = 'logs/'
    # log_path = '/opt/python' + '/logs/'
    # print('log_path', log_path)
    if not os.path.exists(log_path):
        os.mkdir(log_path)

    log_name = log_path + rq + '.log'
    logfile = log_name
    fh = logging.FileHandler(logfile)
    fh.setLevel(logging.DEBUG)  # 输出到file的log等级的开关
    # 第三步，定义handler的输出格式
    formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
    fh.setFormatter(formatter)
    # 第四步，将logger添加到handler里面
    logger.addHandler(fh)
    return logger


def add_camera_car(vehiclePicInfo):
    q_point = QPointF()
    q_point.setX(lon)
    q_point.setY(-lat)
    # 获取离目标点最近的坐标，共9个单元格，一般 lLocation是最近的
    l_location = net_iface.locateOnCrid(q_point, 9)
    # print("l_location", l_location)
    # 判断获取到最近的坐标集合是否为空
    if len(l_location) > 0:
        p_lane_object = l_location[0].pLaneObject
        # 路段发车
        print(p_lane_object, ILane)
        if isinstance(p_lane_object, ILane):
            l_link = p_lane_object.link()
            ll_id = l_link.id()
            sec_from_connect_link = l_link.fromConnectors()
            if len(sec_from_connect_link) > 0:
                iConnector = sec_from_connect_link[0]
                lLink = iConnector.fromLink()
                ll_id = lLink.id()
                # print('上游道路id', lLink.id())
            # 发车信息初始化
            dvp = Online.DynaVehiParam()
            dvp.vehiTypeCode = car_real_type[car['vehicleType']]
            # 根据车辆类型在指定车道发车（机动车仅能在机动车道行驶，非机动车(5,6,7)则能在所有车道行驶） 目前能够精确到具体车道
            dvp.laneNumber = p_lane_object.number()
            # 这里理论上需要计算发车点距离路段起点的位置
            # （会首先获取当前车道所有的起点位置，计算起点位置距离车辆经纬度的距离，作为发车点距离路段起点的距离）
            dvp.roadId = l_link.id()
            dvp.dist = l_location[0].distToStart
            dvp.speed = 0
            dvp.color = f"#FF0000"
            # print('主车所在道路ID:', dvp.roadId, '所在车道', dvp.laneNumber)

            print("创建主车", l_link.id())
            vehicle = simu_iface.createGVehicle(dvp, True)
            if vehicle is not None:
                self.target_start_car_dict[vehicle.id()] = carId
            else:
                # pass
                print('路段车辆创建失败')

        # 连接段发车
        else:
            # 发车信息初始化
            dvp = Online.DynaVehiParam()
            dvp.vehiTypeCode = car_real_type[car['vehicleType']]
            # 获取连接段
            connector = p_lane_object.connector()
            # 根据车辆类型在指定车道发车（机动车仅能在机动车道行驶，非机动车(5,6,7)则能在所有车道行驶） 目前能够精确到具体车道
            from_link = connector.fromLink()
            dvp.laneNumber = random.randint(1, 2)
            # 这里理论上需要计算发车点距离路段起点的位置
            # （会首先获取当前车道所有的起点位置，计算起点位置距离车辆经纬度的距离，作为发车点距离路段起点的距离）
            dvp.roadId = from_link.id()
            dvp.dist = from_link.length() - 1
            dvp.speed = 0
            dvp.color = f"#4169E1"
            vehicle = simu_iface.createGVehicle(dvp, True)
            print("创建主车", from_link.id())
            if vehicle is not None:
                self.target_start_car_dict[vehicle.id()] = carId
            else:
                print("连接段创建车辆失败")


def main(sumo_cfg_file=None, sumo_net_file=None, gui=True):
    sumo_net_instance = sumolib.net.readNet(sumo_net_file, withInternal=True, withLatestPrograms=True)
    sumo_utils.start_sumo(sumo_cfg_file, False, gui=True)
    # 设置所有车道的最大通行速度
    for id in traci.lane.getIDList():
        traci.lane.setMaxSpeed(id, 50)
    traci.polygon.add('GLOBAL_POLYGON_CENTER', GLOBAL_POLYGON_CENTER, (1, 0, 1))
    traci.polygon.subscribeContext('GLOBAL_POLYGON_CENTER',
                                   tc.CMD_GET_VEHICLE_VARIABLE, 10000,
                                   [tc.VAR_SPEED, tc.VAR_DECEL, tc.VAR_DISTANCE, tc.VAR_TYPE, tc.VAR_POSITION,
                                    tc.VAR_ROAD_ID, tc.VAR_LANE_INDEX, tc.VAR_LANE_ID, tc.VAR_ACCEL, tc.VAR_ANGLE,
                                    tc.VAR_LANE_ID, tc.VAR_ACCELERATION, tc.VAR_LANE_INDEX,
                                    tc.TRAFFICLIGHT_TYPE_STATIC])
    traci.simulation.subscribe([tc.VAR_ARRIVED_VEHICLES_NUMBER,
                                tc.VAR_ARRIVED_VEHICLES_IDS,
                                tc.VAR_DEPARTED_VEHICLES_NUMBER,
                                tc.VAR_DEPARTED_VEHICLES_IDS,
                                tc.VAR_COLLIDING_VEHICLES_NUMBER,
                                tc.VAR_COLLIDING_VEHICLES_IDS])
    # 获取虚拟设备状态kafka数据
    vir_thread = threading.Thread(target=kafka_util.receive_message_of_ETC_vehicle)
    vir_thread.start()
    ws_server = WebSocketServer()
    ws_server.start()

    EdgeID, Pos, LaneIndex = traci.simulation.convertRoad(114.129724,30.572269, True)
    EdgeID1, Pos1, LaneIndex1 = traci.simulation.convertRoad(114.129755,30.572247, True)
    EdgeID2, Pos2, LaneIndex2 = traci.simulation.convertRoad(114.129770,30.572213, True)
    routeID = str(uuid.uuid1())
    traci.route.add(routeID, [EdgeID])
    routeID1 = str(uuid.uuid1())
    traci.route.add(routeID1, [EdgeID1])
    routeID2 = str(uuid.uuid1())
    traci.route.add(routeID2, [EdgeID2])

    # print(EdgeID, Pos, LaneIndex)
    # print(EdgeID1, Pos1, LaneIndex1)
    # print(EdgeID2, Pos2, LaneIndex2)

    posDict = {"1": {"pos": Pos, "route": routeID}, "2": {"pos": Pos1, "route": routeID1},
               "3": {"pos": Pos2, "route": routeID2}}
    logger = get_logger("simulation")
    # f = open("data//data0908v1.json", encoding='utf-8')
    try:
        # f = open("../data//data0908v1.json", encoding='utf-8')
        loop = asyncio.get_event_loop()
        while (True):
            try:
                # line = f.readline().strip()
                # if line:
                if not real_vehicle_queue.empty():
                    # vehiclePicInfo = json.loads(line)
                    vehiclePicInfo = real_vehicle_queue.get(block=False)
                    add_camera_car(vehiclePicInfo)
                    # if line:
                    #     vehiclePicInfo = json.loads(line)
                    unlawfulMold = vehiclePicInfo["unlawfulMold"]
                    dg = vehiclePicInfo["dangerousGoods"]
                    if "危化" in str(dg):
                   # if int(dg) == 1:
                        unlawfulMold = "0103"
                    if vehiclePicInfo["identifyType"] == 3 or vehiclePicInfo["identifyType"] == 4:
                        unlawfulMold = "0104"
                    # 1 小客车   3 大巴车 15 大货车
                    if 1 <= vehiclePicInfo['identifyType'] <= 2:
                        typeid = '1'
                    elif 11 <= vehiclePicInfo['identifyType'] <= 26:
                        typeid = '15'
                    elif 3 <= vehiclePicInfo['identifyType'] <= 4:
                        typeid = '3'
                    licenseCode = ""
                    if "默" not in vehiclePicInfo["licenseCode"]:
                        licenseCode = vehiclePicInfo["licenseCode"]
                    else:
                        if "etcLicense" in vehiclePicInfo.keys() and  len(vehiclePicInfo["etcLicense"]) > 0:
                            licenseCode = vehiclePicInfo["etcLicense"]
                    if len(licenseCode) > 0:
                        if len(unlawfulMold) > 0:
                            traci.vehicle.add(
                                vehID=str(licenseCode.encode('UTF-8')) + "_" + str(
                                    vehiclePicInfo['recordId']) + "_" + unlawfulMold,
                                routeID=posDict[vehiclePicInfo['headLaneNum']]["route"],
                                typeID=typeid, depart='0', departPos=posDict[vehiclePicInfo['headLaneNum']]["pos"],
                                departLane=str(int(vehiclePicInfo['headLaneNum']) - 1)
                                if 'headLaneNum' in vehiclePicInfo.keys() else str(random.randint(0, 2)),
                                departSpeed=str(vehiclePicInfo['vehicleSpeed'] / 3.6))
                        else:
                            traci.vehicle.add(
                                vehID=str(licenseCode.encode('UTF-8')) + "_" + str(
                                    vehiclePicInfo['recordId']),
                                routeID=posDict[vehiclePicInfo['headLaneNum']]["route"],
                                typeID=typeid, depart='0', departPos=posDict[vehiclePicInfo['headLaneNum']]["pos"],
                                departLane=str(int(vehiclePicInfo['headLaneNum']) - 1)
                                if 'headLaneNum' in vehiclePicInfo.keys() else str(random.randint(0, 2)),
                                departSpeed=str(vehiclePicInfo['vehicleSpeed'] / 3.6))

                global_vehicles = traci.polygon.getContextSubscriptionResults('GLOBAL_POLYGON_CENTER')
                car_list = list()
                # print(len(global_vehicles))
                for vehicle_id, veh_info in dict(global_vehicles).items():
                    if True:
                        pos = veh_info[tc.VAR_POSITION]
                        longitude, latitude = sumo_utils.xyConversionlatAndLon(sumo_net_instance, pos)
                        speed = veh_info[tc.VAR_SPEED]
                        vehicle_type = veh_info[tc.VAR_TYPE]
                        info = vehicle_id.split("_")
                        unlawfulMold = ""

                        vId = info[1]
                        licenseCode = info[0]
                        if vehicle_type == "3":
                            vehicle_type = "6"
                        if vehicle_type == "15":
                            vehicle_type = "3"
                        if len(info) == 3:
                            unlawfulMold = info[2]
                            if unlawfulMold == "0103":
                                vehicle_type = "8"
                        if (unlawfulMold[:4] == "0102" or unlawfulMold[:4] == "0103") :
                            unlawfulMold = ""
                        if unlawfulMold == "0104":
                            unlawfulMold = "0103"
                        car = {"id": vId, "vehicleType": vehicle_type, "longitude": longitude,
                               "latitude": latitude,
                               "courseAngle": veh_info[tc.VAR_ANGLE], "acceleration": veh_info[tc.VAR_ACCELERATION],
                               "speed": round(speed * 3.6, 2), "laneNum": veh_info[tc.VAR_LANE_INDEX],
                               "licenseode": eval(licenseCode).decode('utf-8'),
                               "unlawfulMold": unlawfulMold,
                               "unlawfulCode": unlawfulMap[unlawfulMold[:4]] if unlawfulMold[:4] in unlawfulMap.keys() else "",
                               }
                        
                        car_list.append(car)

                result = {"e1FrameParticipant": car_list, "participantNum": len(car_list),
                          "timeStamp": str(time.time()),
                          "globalTimeStamp": str(time.time())}
                logger.info(result)
                loop.run_until_complete(ws_server.broadcast(str(result).replace("'", '"')))
                # websocketserver.test("1111")
                traci.simulationStep()
                time.sleep(0.05)
            except Exception as e:
                traci.simulationStep()
                time.sleep(0.05)
                logging.exception(str(e))
                continue

    except Exception as e:
        logging.exception(str(e))


if __name__ == "__main__":
    # sumo_net_file = r"D:\工作\项目\速通高速\fengtai_etc_sumo-image\config\0815-v1.net.xml"  # 路网文件
    # sumo_cfg_file = r"D:\工作\项目\速通高速\fengtai_etc_sumo-image\config\fengtai.sumocfg"  # 路网文件
    # logger = get_logger("simulation")
    # logger.info("test")
    #
    # main(sumo_cfg_file=sumo_cfg_file, sumo_net_file=sumo_net_file)
    sumo_net_file = "./config/2.net.xml"  # 路网文件
    sumo_cfg_file = "./config/hubeiqintai.sumocfg"  # 路网文件
    main(sumo_cfg_file=sumo_cfg_file, sumo_net_file=sumo_net_file)
